/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package peoplesoftsimulator;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.forgerock.opendj.ldap.Connection;
import org.forgerock.opendj.ldap.Entries;
import org.forgerock.opendj.ldap.Entry;
import org.forgerock.opendj.ldap.ErrorResultException;
import org.forgerock.opendj.ldap.LDAPConnectionFactory;
import org.forgerock.opendj.ldap.LinkedHashMapEntry;
import org.forgerock.opendj.ldap.SearchScope;
import org.forgerock.opendj.ldap.TreeMapEntry;
import org.forgerock.opendj.ldap.requests.ModifyRequest;

/**
 * The PeopleSoft simulator is built to reproduce the actions of the PeopleSoft software.
 * PeopleSoft software generates XML data for actions like adding, modifying or terminating
 * employees from the PeopleSoft database. To bridge this data we made copies of XML transactions
 * generated by PeopleSoft and created this program to parse the XML from a file as if it where sent
 * over the network.
 * @author anvil
 */
public class PeopleSoftSimulator {

    /**
     * The main method will accept the url that the LDAP is hosted on,
     * the port that the LDAP directory uses,
     * and the XML file containing a copy of actual PeopleSoft data.
     * 
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        System.out.println("Initializing Simulator...");

        System.out.println("Parsing arguments...");

        String url = args[0];
        String port = args[1];
        String xml_file = args[2];

        System.out.println("Parsed arguments:");
        System.out.println("\turl: " + url);
        System.out.println("\turl: " + port);
        System.out.println("\turl: " + xml_file);

        System.out.println("Connecting to url...");

        try {
            StringBuffer sb = new StringBuffer();
            File file = new File(xml_file);

            BufferedReader br = new BufferedReader(new FileReader(file));

            int read = br.read();

            while (read != -1) {
                sb.append((char) read);

                read = br.read();
            }

            System.out.println("Sending XML...");

            HashMap<String, Object> lol = new HashMap();
            lol = peoplesoftsimulator.Parse1.parseXML(sb.toString(), "/home/anvil/Desktop/XML_TEST/generated/newxml.xml");
            processXMLData(lol);

        } catch (FileNotFoundException ex) {
            System.out.println("Error parsing xml. Invalid XML.");
        } catch (IOException ex) {
            Logger.getLogger(PeopleSoftSimulator.class.getName()).log(Level.SEVERE, null, ex);
        }

        System.out.println("Simulator Shutdown.");
    }

    /**
     * Parse XML data from hashmap to make meaningful decisions on what actions to take with data.
     * @param xml - parsed data from XML containing all attributes and values to be added.
     */
    public static void processXMLData(HashMap<String, Object> xml) {
        ArrayList<String> audit_type = (ArrayList<String>) xml.get("AUDIT_ACTN");

        if (audit_type != null) {
            for (int x = 0; x < audit_type.size(); x++) {
                String a = audit_type.get(x);

                switch (a) {
                    case "A":
                        add(x, xml);

                        break;
                    case "C":
                        modify(x, xml);

                        break;
                    case "D":
                        terminate(x, xml);

                        break;
                }
            }
        }
    }

    /**
     * Method to add entry to the ldap database. Will use parameter set provided
     * by the XML parser.
     * @param x - the reference value for XML data.
     * @param xml - parsed data from XML containing all attributes and values to be added.
     */
    private static void add(int x, HashMap<String, Object> xml) {
        ArrayList<String> PHONE = (ArrayList<String>) xml.get("PHONE");
        ArrayList<String> BIRTHDAY = (ArrayList<String>) xml.get("BIRTHDAY");
        ArrayList<String> FIRSTNAME = (ArrayList<String>) xml.get("FIRSTNAME");
        ArrayList<String> STATE = (ArrayList<String>) xml.get("STATE");
        ArrayList<String> COUNRTY = (ArrayList<String>) xml.get("COUNRTY");
        ArrayList<String> POSTAL = (ArrayList<String>) xml.get("POSTAL");
        ArrayList<String> ADDRESS = (ArrayList<String>) xml.get("ADDRESS");
        ArrayList<String> EMPLID = (ArrayList<String>) xml.get("EMPLID");
        ArrayList<String> EMAIL = (ArrayList<String>) xml.get("EMAIL");
        ArrayList<String> LASTNAME = (ArrayList<String>) xml.get("LASTNAME");

        Entry entry = new LinkedHashMapEntry("uid=" + EMPLID.get(0) + ",ou=People,dc=demo,dc=com")
                .addAttribute("objectclass", "top")
                .addAttribute("objectclass", "person")
                .addAttribute("objectclass", "organizationalPerson")
                .addAttribute("objectclass", "inetOrgPerson");

        if (PHONE != null && x < PHONE.size()) {
            entry.addAttribute("telephoneNumber", PHONE.get(x));
        }

        if (BIRTHDAY != null && x < BIRTHDAY.size()) {
            //entry.addAttribute("", BIRTHDAY.get(x));
        }

        if (FIRSTNAME != null && x < FIRSTNAME.size()) {
            entry.addAttribute("givenName", FIRSTNAME.get(x));
            entry.addAttribute("cn", FIRSTNAME.get(x));
        }

        if (STATE != null && x < STATE.size()) {
            entry.addAttribute("st", STATE.get(x));
        }

        if (COUNRTY != null && x < COUNRTY.size()) {
            //entry.addAttribute("", COUNRTY.get(x));
        }

        if (POSTAL != null && x < POSTAL.size()) {
            entry.addAttribute("postalCode", POSTAL.get(x));
        }

        if (ADDRESS != null && x < ADDRESS.size()) {
            entry.addAttribute("street", ADDRESS.get(x));
        }

        if (EMPLID != null && x < EMPLID.size()) {
            entry.addAttribute("uid", EMPLID.get(x));
        }

        if (EMAIL != null && x < EMAIL.size()) {
            entry.addAttribute("mail", EMAIL.get(x));
        }

        if (LASTNAME != null && x < LASTNAME.size()) {
            entry.addAttribute("sn", LASTNAME.get(x));
        }

        final LDAPConnectionFactory factory = new LDAPConnectionFactory("localhost", 389);
        Connection connection = null;
        try {
            String adminDN = "cn=Directory Manager";
            char[] adminPwd = "password".toCharArray();

            connection = factory.getConnection();
            connection.bind(adminDN, adminPwd);

            System.out.println("Creating an entry...");

            connection.add(entry);
        } catch (final ErrorResultException e) {
            System.err.println(e.getMessage());
            //System.exit(e.getResult().getResultCode().intValue());
        } finally {
            if (connection != null) {
                connection.close();
            }
        }
    }

    /**
     * Method to terminate entry in the ldap database. Will use parameter set provided
     * by the XML parser.
     * @param x - the reference value for XML data.
     * @param xml - parsed data from XML containing all attributes and values to be terminated.
     */
    private static void terminate(int x, HashMap<String, Object> xml) {
        ArrayList<String> EMPLID = (ArrayList<String>) xml.get("EMPLID");

        final LDAPConnectionFactory factory = new LDAPConnectionFactory("localhost", 389);
        Connection connection = null;
        try {
            String adminDN = "cn=Directory Manager";
            char[] adminPwd = "password".toCharArray();

            connection = factory.getConnection();
            connection.bind(adminDN, adminPwd);

            System.out.println("Terminating entry...");

            connection.delete("uid=" + EMPLID.get(0) + ",ou=People,dc=demo,dc=com");
        } catch (final ErrorResultException e) {
            System.err.println(e.getMessage());
            //System.exit(e.getResult().getResultCode().intValue());
        } finally {
            if (connection != null) {
                connection.close();
            }
        }
    }

    /**
     * Method to modify entry in the ldap database. Will use parameter set provided
     * by the XML parser.
     * @param x - the reference value for XML data.
     * @param xml - parsed data from XML containing all attributes and values to be modified.
     */
    private static void modify(int x, HashMap<String, Object> xml) {
        ArrayList<String> PHONE = (ArrayList<String>) xml.get("PHONE");
        ArrayList<String> BIRTHDAY = (ArrayList<String>) xml.get("BIRTHDAY");
        ArrayList<String> FIRSTNAME = (ArrayList<String>) xml.get("FIRSTNAME");
        ArrayList<String> STATE = (ArrayList<String>) xml.get("STATE");
        ArrayList<String> COUNRTY = (ArrayList<String>) xml.get("COUNRTY");
        ArrayList<String> POSTAL = (ArrayList<String>) xml.get("POSTAL");
        ArrayList<String> ADDRESS = (ArrayList<String>) xml.get("ADDRESS");
        ArrayList<String> EMPLID = (ArrayList<String>) xml.get("EMPLID");
        ArrayList<String> EMAIL = (ArrayList<String>) xml.get("EMAIL");
        ArrayList<String> LASTNAME = (ArrayList<String>) xml.get("LASTNAME");

        final LDAPConnectionFactory factory = new LDAPConnectionFactory("localhost", 389);
        Connection connection = null;
        try {
            String adminDN = "cn=Directory Manager";
            char[] adminPwd = "password".toCharArray();

            connection = factory.getConnection();
            connection.bind(adminDN, adminPwd);

            System.out.println("Modify entry...");

            Entry entry = connection.searchSingleEntry("uid=" + EMPLID.get(0) + ",ou=People,dc=demo,dc=com", SearchScope.WHOLE_SUBTREE, "(objectClass=*)", "*");
            
            Entry old = TreeMapEntry.deepCopyOfEntry(entry);

            if (PHONE != null && x < PHONE.size()) {
                entry.replaceAttribute("telephoneNumber", PHONE.get(x));
            }

            if (BIRTHDAY != null && x < BIRTHDAY.size()) {
                //entry.replaceAttribute("", BIRTHDAY.get(x));
            }

            if (FIRSTNAME != null && x < FIRSTNAME.size()) {
                entry.replaceAttribute("givenName", FIRSTNAME.get(x));
                entry.replaceAttribute("cn", FIRSTNAME.get(x));
            }

            if (STATE != null && x < STATE.size()) {
                entry.replaceAttribute("st", STATE.get(x));
            }

            if (COUNRTY != null && x < COUNRTY.size()) {
                //entry.replaceAttribute("", COUNRTY.get(x));
            }

            if (POSTAL != null && x < POSTAL.size()) {
                entry.replaceAttribute("postalCode", POSTAL.get(x));
            }

            if (ADDRESS != null && x < ADDRESS.size()) {
                entry.replaceAttribute("street", ADDRESS.get(x));
            }

            if (EMPLID != null && x < EMPLID.size()) {
                entry.replaceAttribute("uid", EMPLID.get(x));
            }

            if (EMAIL != null && x < EMAIL.size()) {
                entry.replaceAttribute("mail", EMAIL.get(x));
            }

            if (LASTNAME != null && x < LASTNAME.size()) {
                entry.replaceAttribute("sn", LASTNAME.get(x));
            }

            ModifyRequest request = Entries.diffEntries(old, entry);
            connection.modify(request);
        } catch (final ErrorResultException e) {
            System.err.println(e.getMessage());
            //System.exit(e.getResult().getResultCode().intValue());
        } finally {
            if (connection != null) {
                connection.close();
            }
        }
    }
}
